package simulationEngine;

import javax.swing.JOptionPane;

import datatypes.LogicalNetworkActionType;
import datatypes.NetworkAction;
import datatypes.PhysicalNetworkActionType;

public class ApplicationLayerScheduler {

	//with guarantee that an lost Message will cause an signal from Network
	private boolean withLostGuarantee = true;
	//with sending an ack in Routing Protocol, that an Message has received
	private boolean withReceiveReply = false;
	private SimulationEngine engine;

	public ApplicationLayerScheduler(SimulationEngine engine) {
		this.engine = engine;
	}

	public void init() {}

	public void execute (NetworkAction action){
		switch (action.getLogType()){
		case SEND_MESSAGE:
			//Send message in Miniworld is called by Higher-Layer-API (or Message Lost-Reply==Could Not Sended), this will inforce
			//the calculation for Network-Actions in the Processor,
			//the call in processor, calculates the pysical Route through the Network
			JOptionPane.showMessageDialog(null, "Fehler im " + this.getClass(),
					"Send Message darf nicht auftreten?",
					JOptionPane.INFORMATION_MESSAGE);
			break;
		case RECEIVE_MESSAGE:
			//Receive Message means not an Signal to the Sender when Message arrived,
			//it means that the Message has received the target, and must be forwarded
			//to higher protocol
			//calls the API from Miniworld, and this will call the Api from the specific Higher-Protocol-Implementation
			engine.getMiniworld().receiveLogicalMessage(action.getMessage(), action.getOriginHost(), action.getTargetHost());
			if (this.withReceiveReply){
				action.changeTypeOfAction(PhysicalNetworkActionType.RECEIVE_MESSAGE, LogicalNetworkActionType.SEND_ACK);
				this.appendNextAction(action);
			}
			break;
		case MESSAGE_LOST:
			//with guarantee that an lost Message will cause an signal from Network
			if (withLostGuarantee){
				action.changeTypeOfAction(PhysicalNetworkActionType.SEND_MSG_LOST, LogicalNetworkActionType.TRACKING_MESSAGE );	
			} else {
				//TODO:call log?
			}
			break;
		case TRACKING_MESSAGE:
			//with guarantee that an Received Message will cause an ACK-Signal
			engine.getMiniworld().trackLogicalMessage(action);				
			break;
		case SEND_SIGNAL_MSG_RECEIVED:
			//This invokes an Message received signal to the initial sender
			//if this option is enabled
			//with guarantee that an Received Message will cause an ACK
			if (action.isSourceReached() && this.withReceiveReply){
				engine.getMiniworld().invokeLogicalMessageReceivedAckSignal(action);
			} else {
				JOptionPane.showMessageDialog(null, "Fehler im " + this.getClass(),
						"Send signal msg Received Error!",
						JOptionPane.ERROR_MESSAGE);				
			}
			break;
		case SEND_ACK:
			//TRACKING OF ACK?
			//nothing else TODO?
			break;
		case SEND_SIGNAL_ACK_LOST:
			//This invokes an TimeoutMechanism
			//after this Timeout-Mechanism a signal will be sended to the higher API of the 
			//origin source, that contains the information, that Message has not been sended.
			if (this.withReceiveReply && this.withLostGuarantee){
				action.changeTypeOfAction(PhysicalNetworkActionType.DO_NOTHING, LogicalNetworkActionType.TIMEOUT);				
				this.appendNextAction(action);
			}
			break;
		case TIMEOUT:
			if (action.isSourceReached()){
				engine.getMiniworld().sendSignalLogicalMessageLost(action);
			} else {
				action.uncount();
				this.appendNextAction(action);
			}
			break;
		case INQUIRY_SCAN:
			engine.getMiniworld().invokeInquiryScan(action);
			break;
		case PAGING:
			engine.getMiniworld().tryToConnectTo(action.getOriginHost(), action.getTargetHost());
			break;
		case PAGING_FAILED:
			engine.getMiniworld().invokePagingFailed(action);
			break;
		case PAGING_SUCCESS:
			engine.getMiniworld().invokePagingSuccessed(action);
			break;
		}

	}
	private void appendNextAction (NetworkAction nextAction){
		engine.getSimulationEnviroment().getQueue().addActionForNextStep(nextAction);
	}
}
